﻿using Database.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Database.Context
{
    public class EFLoggerProvider : ILoggerProvider
    {
        public ILogger CreateLogger(string categoryName) => new EFLogger(categoryName);
        public void Dispose() { }
    }

    public class EFLogger : ILogger
    {
        private readonly string categoryName;

        public EFLogger(string categoryName) => this.categoryName = categoryName;

        public bool IsEnabled(LogLevel logLevel) => true;

        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {

            if (categoryName == "Microsoft.EntityFrameworkCore.Database.Command"
                    && logLevel == LogLevel.Information)
            {
                var logContent = formatter(state, exception);

                Console.WriteLine();
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine(logContent);
                Console.ResetColor();
            }
        }

        public IDisposable BeginScope<TState>(TState state) => null;
    }
    public class DatabaseContext : DbContext
    {
        public DatabaseContext(DbContextOptions<DatabaseContext> options)
             : base(options)
        {
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            var loggerFactory = new LoggerFactory();
            loggerFactory.AddProvider(new EFLoggerProvider());
            optionsBuilder.UseLoggerFactory(loggerFactory);
            optionsBuilder.EnableSensitiveDataLogging(true);
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            var cascadeFKs = modelBuilder.Model.GetEntityTypes()
                .SelectMany(t => t.GetForeignKeys())
                .Where(fk => !fk.IsOwnership && fk.DeleteBehavior == DeleteBehavior.Cascade);

            foreach (var fk in cascadeFKs)
            {
                fk.DeleteBehavior = DeleteBehavior.Restrict;
            }
            base.OnModelCreating(modelBuilder);
        }

        public int SaveChangesWithAudit(string operatorName, bool needUpdateTime = true)
        {
            foreach (var addedItem in this.ChangeTracker.Entries().Where(p => p.State == EntityState.Added))
            {
                if (addedItem.Entity is EntityBase)
                {
                    var convertedItem = (EntityBase)addedItem.Entity;
                    if (needUpdateTime)
                    {
                        convertedItem.Created_Time = DateTime.Now;
                        convertedItem.Updated_Time = DateTime.Now;
                    }

                    convertedItem.Created_By = operatorName ?? string.Empty;
                    convertedItem.Updated_By = operatorName ?? string.Empty;
                    convertedItem.Id = Guid.NewGuid();
                }
            }

            foreach (var updatedItem in this.ChangeTracker.Entries().Where(p => p.State == EntityState.Modified))
            {
                if (updatedItem.Entity is EntityBase)
                {
                    var convertedItem = (EntityBase)updatedItem.Entity;

                    if (needUpdateTime)
                    {
                        convertedItem.Updated_Time = DateTime.Now;
                    }

                    convertedItem.Updated_By = operatorName ?? string.Empty;
                }
            }

            return base.SaveChanges();
        }


        public virtual DbSet<ExamInfo> ExamInfos { get; set; }
    }
}
